from typing import Any

from fastapi import HTTPException, Request, status, FastAPI
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from starlette.responses import JSONResponse

from app.core.log import logger
from app.enums.error import ErrorCodeEnum, TokenErrorEnum
from app.schemas.base_schema import ApiResult


class BusinessException(HTTPException):
    """ 业务异常 """

    def __init__(self, message: str | None = None, headers: dict[str, Any] | None = None):
        super().__init__(
            ErrorCodeEnum.ERR_BUSINESS.code,
            message or ErrorCodeEnum.ERR_BUSINESS.message,
            headers
        )
        self.code = ErrorCodeEnum.ERR_BUSINESS.code
        self.message = message or ErrorCodeEnum.ERR_BUSINESS.message


class ArgumentException(HTTPException):
    """ 参数异常 """

    def __init__(self, message: str | None = None, headers: dict[str, Any] | None = None):
        super().__init__(
            ErrorCodeEnum.ERR_ARGUMENT.code,
            message or ErrorCodeEnum.ERR_ARGUMENT.message,
            headers
        )
        self.code = ErrorCodeEnum.ERR_ARGUMENT.code
        self.message = message or ErrorCodeEnum.ERR_ARGUMENT.message


class TokenException(HTTPException):
    """ token异常 """

    def __init__(self, error_enum: TokenErrorEnum, headers: dict[str, Any] | None = None):
        super().__init__(error_enum.code, error_enum.message, headers)
        self.code = error_enum.code
        self.message = error_enum.message


class SameTokenException(HTTPException):
    """ same-token异常 """

    def __init__(self, message: str | None = None, headers: dict[str, Any] | None = None):
        super().__init__(
            ErrorCodeEnum.ERR_SAME_TOKEN.code,
            message or ErrorCodeEnum.ERR_SAME_TOKEN.message,
            headers
        )
        self.code = ErrorCodeEnum.ERR_SAME_TOKEN.code
        self.message = message or ErrorCodeEnum.ERR_SAME_TOKEN.message


class LimitException(HTTPException):
    """ 限流异常 """

    def __init__(self, code: int | None = None, message: str | None = None, headers: dict[str, Any] | None = None):
        super().__init__(
            code or ErrorCodeEnum.TOO_MANY_REQUESTS.code,
            message or ErrorCodeEnum.TOO_MANY_REQUESTS.message,
            headers
        )
        self.code = code or ErrorCodeEnum.TOO_MANY_REQUESTS.code
        self.message = message or ErrorCodeEnum.TOO_MANY_REQUESTS.message


class NotPermissionException(HTTPException):
    """ 权限异常 """

    def __init__(self, permission: str, headers: dict[str, Any] | None = None):
        super().__init__(
            ErrorCodeEnum.FAIL.code,
            permission,
            headers
        )
        self.code = ErrorCodeEnum.FAIL.code
        self.message = f"无此权限：{permission}"


class NotRoleException(HTTPException):
    """ 角色异常 """

    def __init__(self, role: str, headers: dict[str, Any] | None = None):
        super().__init__(
            ErrorCodeEnum.FAIL.code,
            role,
            headers
        )
        self.code = ErrorCodeEnum.FAIL.code
        self.message = f"无此角色：{role}"


def init_exception_handler(app: FastAPI) -> None:
    """ 异常处理 """

    @app.exception_handler(BusinessException)
    async def business_exception_handler(_: Request, exc: BusinessException):
        """ 业务异常处理 """
        logger.exception("抛出业务异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_400_BAD_REQUEST,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(ArgumentException)
    async def argument_exception_handler(_: Request, exc: ArgumentException):
        """ 参数异常处理 """
        logger.exception("抛出参数异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_400_BAD_REQUEST,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(TokenException)
    async def token_exception_handler(_: Request, exc: TokenException):
        """ 登录认证异常处理 """
        logger.exception("抛出登录认证异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(SameTokenException)
    async def same_token_exception_handler(_: Request, exc: SameTokenException):
        """ same-token异常处理 """
        logger.exception("抛出same-token异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_401_UNAUTHORIZED,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(LimitException)
    async def limit_exception_handler(_: Request, exc: LimitException):
        """ 限流异常处理 """
        logger.exception("抛出限流异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_429_TOO_MANY_REQUESTS,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(NotPermissionException)
    async def not_permission_exception_handler(_: Request, exc: NotPermissionException):
        """ 抛出权限异常 """
        logger.exception("抛出权限异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_403_FORBIDDEN,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(NotRoleException)
    async def not_role_exception_handler(_: Request, exc: NotRoleException):
        """ 抛出角色异常 """
        logger.exception("抛出角色异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_403_FORBIDDEN,
            content=jsonable_encoder(ApiResult.result(code=exc.code, message=exc.message))
        )

    @app.exception_handler(ValueError)
    async def value_error_handler(_: Request, exc: ValueError):
        """ 值异常处理 """
        logger.exception("抛出值异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_400_BAD_REQUEST,
            content=jsonable_encoder(ApiResult.result(code=400, message=str(exc.args)))
        )

    @app.exception_handler(RequestValidationError)
    async def request_validation_error_handler(_: Request, exc: RequestValidationError):
        """ 请求参数验证异常处理 """
        logger.exception("抛出请求参数验证异常：", exc)
        # 简化错误信息
        simple_error_messages = []
        for error in exc.errors():
            simple_error_messages.append({
                "type": error["type"],
                "field": ".".join(error["loc"]),
                "message": error["msg"]
            })

        return JSONResponse(
            status_code=status.HTTP_400_BAD_REQUEST,
            content=jsonable_encoder(
                ApiResult.result(
                    code=ErrorCodeEnum.ERR_REQUEST_PARAM_VALIDATION_EXCEPTION.code,
                    message=ErrorCodeEnum.ERR_REQUEST_PARAM_VALIDATION_EXCEPTION.message,
                    error=simple_error_messages
                ))
        )

    @app.exception_handler(Exception)
    async def exception_handler(_: Request, exc: Exception):
        """ 异常处理 """
        logger.exception("抛出其它异常：", exc)
        return JSONResponse(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            content=jsonable_encoder(
                ApiResult.result(
                    code=ErrorCodeEnum.SYSTEM_BUSY.code,
                    message=ErrorCodeEnum.SYSTEM_BUSY.message,
                    error=str(exc.args))
            )
        )
